package model;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
 *  FileManager is the class used to save persistent data for the Visits
 *  lookup application. 
 * @author Craig Markham
 * @version 2-18-12
 */
public class FileManager {

	/**
	 * The relative File Path for the file.
	 */
	private static String my_path;
	//private static String my_path = ".//src//data//"; //Mac file path

	/**
	 * The File name for the Visit data.
	 */
	private static String my_VisitXML;
	
	/**
	 * The List of Visits for the file.
	 */
	private List<Visit> my_visits = new ArrayList<Visit>();
	
	/**
	 * Default Constructor for FileManager.
	 */
	public FileManager(){

		my_path = ".\\data\\";
		my_VisitXML = "AllVisitsWithAddresses2.xml";

	}
	
	/**
	 * Constructor for FileManager.
	 * @param the_path The relative path for the data files.
	 * @param the_VisitXML The file name for the Visit file.

	 * @Pre Parameter must not be null,
	 */
	public FileManager(String the_path, String the_VisitXML){

		my_path = the_path;
		my_VisitXML = the_VisitXML;

	}

	/**
	 * Returns a list of Users from the data file.
	 * 
	 * @return my_visits The list of Visits from the data file.
	 */
	public List<Visit> loadVisitData(){
		//for testing purposes only
		//testUserData();
		
		FileManager.XPathReader reader = this.new XPathReader(my_path. concat(my_VisitXML));
		NodeList totalVisits = (NodeList)reader.read("/dataroot /AllVisitsWithAddresses2", XPathConstants.NODESET);
		for(int i = 1; i <= totalVisits.getLength(); i++){
			String expression = "/dataroot /AllVisitsWithAddresses2[" + i + "]";
			NodeList visit = (NodeList)reader.read(expression, 
			XPathConstants.NODESET);
			traverseVisits(visit);
		}
		return my_visits;
	}
	
	/**
	 * Saves the specified lists of Users and Jobs to a data file.
	 * 
	 * @param the_jobs The list of Jobs for the data file.
	 * @param the_users The list of Users for the data file.
	 * @return my_error Returns False if there was an error saving 
	 * the data file.
	 */
	public boolean saveData(List<Visit> the_visits){
		boolean my_error = true;
		my_error = (createVisitsXML(the_visits));
		return my_error;
	}
	
	
	/**
	 * Writes the list of Users to be saved to data file.
	 * 
	 * @param the_users The list of Users from the data file.
	 * @return my_error Returns False if there was an error saving 
	 * the data file.
	 */	
	private boolean createVisitsXML(List<Visit> the_visits) {
		boolean my_error = true;
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
	 
			// root elements
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement("AllVisits");
			doc.appendChild(rootElement);
		 
			for(Visit visit : the_visits){
				// visit elements
				Element Visit = doc.createElement("Visit");
				rootElement.appendChild(Visit);
				 
				Element my_visit_id = doc.createElement("ID");
				my_visit_id.appendChild(doc.createTextNode(visit.getVisitID().toString()));
				Visit.appendChild(my_visit_id);
				 
				Element my_origin = doc.createElement("Origin");
				my_origin.appendChild(doc.createTextNode(visit.getOrigin()));
				Visit.appendChild(my_origin);
				
				Element my_destination = doc.createElement("Destination");
				my_destination.appendChild(doc.createTextNode(visit.getDestination()));
				Visit.appendChild(my_destination);

				Element my_mileage = doc.createElement("Mileage");
				my_mileage.appendChild(doc.createTextNode(Integer.toString(visit.getMileage())));
				Visit.appendChild(my_mileage);
				
				Element my_time = doc.createElement("Time");
				my_time.appendChild(doc.createTextNode(Integer.toString(visit.getTime())));
				Visit.appendChild(my_time);

			}
		
		// write the content into xml file
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		DOMSource source = new DOMSource(doc);
		StreamResult result = new StreamResult(new File(my_path.concat(my_VisitXML)));
		transformer.transform(source, result);	 
		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
			my_error = true;
	  	} catch (TransformerException tfe) {
	  		tfe.printStackTrace();
	  	}
	  	return my_error;
	}


	/**
	 * Traverses the Parks List in the ParkManager Node.
	 * 
	 * @param my_rootNode The root Node of the Parks List.
	 */
	private void traverseVisits(NodeList my_rootNode) {
		for(int index = 0; index < my_rootNode.getLength(); index ++){
			NodeList childNodes = my_rootNode.item(index).getChildNodes();

			String my_visit_id = childNodes.item(1).getTextContent();
    		String my_origin = childNodes.item(3).getTextContent();
    		String my_destination = childNodes.item(5).getTextContent();

    		
    		my_visits.add(new Visit(my_visit_id, my_origin, my_destination));
		}
	}
	
	/**
	 * 
	 * @author Craig Markham
	 * @version 2-18-12
	 */
	private class XPathReader {
	    
		/**
		 * The path and name of the XML file.
		 */
	    private String xmlFile;
	    
		/**
		 * The document object of the file.
		 */
	    private Document xmlDocument;
		/**
		 * The xPath expression.
		 */
	    private XPath xPath;
	    

		/**
		 * Default Constructor for XPathReader.
		 */
	    private XPathReader(String xmlFile) {
	        this.xmlFile = xmlFile;
	        initObjects();
	    }
	    
		/**
		 * Initializes the XML Document
		 */
	    private void initObjects(){        
	        try {
	            xmlDocument = DocumentBuilderFactory.newInstance().
	            	newDocumentBuilder().parse(xmlFile);            
	            xPath =  XPathFactory.newInstance().
				newXPath();
	        } catch (IOException ex) {
	            ex.printStackTrace();
	        } catch (SAXException ex) {
	            ex.printStackTrace();
	        } catch (ParserConfigurationException ex) {
	            ex.printStackTrace();
	        }       
	    }
	    
		/**
		 * Reads the XML Document
		 */
	    private Object read(String expression, 
				QName returnType){
	        try {
	            XPathExpression xPathExpression = 
				xPath.compile(expression);
		        return xPathExpression.evaluate
				(xmlDocument, returnType);
	        } catch (XPathExpressionException ex) {
	            ex.printStackTrace();
	            return null;
	        }
	    }
	}
}
